package cn.lghuntfor.commons.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;

/**
 * 链路日志处理过滤器
 * @author liaogang
 * @date 2020/9/10 11:28
 */
@Slf4j
public class RequestLogGatewayFilter implements GlobalFilter, Ordered {

    private static final String START_TIME = "START_TIME";

    @Override
    public int getOrder() {
        /** 用于排序, 值越小越靠前, log优先级最高 */
        return -Integer.MAX_VALUE + 100;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        handleRequestLogInfo(request);
        exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
        return chain.filter(exchange)
                .then(Mono.fromRunnable(() -> elapsedTime(exchange, request)));
    }

    /** 计算调用耗时 */
    private void elapsedTime(ServerWebExchange exchange, ServerHttpRequest req) {
        Long startTime = exchange.getAttribute(START_TIME);
        if (startTime != null) {
            String uri = req.getURI().toString();
            StringBuilder requestInfo = new StringBuilder();
            String method = req.getMethodValue();
            requestInfo.append("====== 请求链接: ").append(method).append(" ").append(uri).append(", elapsed time = {}ms, end ======   ");

            Long executeTime = (System.currentTimeMillis() - startTime);
            log.info(requestInfo.toString(), executeTime);
        }
    }

    /**
     * 请求信息打印
     * @author liaogang
     * @date 2020/9/16
     * @param request
     * @return void
     */
    private void handleRequestLogInfo(ServerHttpRequest request) {
        String uri = request.getURI().toString();
        StringBuilder requestInfo = new StringBuilder();
        String method = request.getMethodValue();
        requestInfo.append("====== 请求链接: ").append(method).append(" ").append(uri).append(", start ======   ");
        this.getHeaders(request, requestInfo);
        this.getParameters(request, requestInfo);
        log.info(requestInfo.toString());
    }

    /**
     * 获取所有header
     * @author liaogang
     * @date 2020/9/16
     * @param request
     * @param requestInfo
     * @return void
     */
    private void getHeaders(ServerHttpRequest request, StringBuilder requestInfo) {
        HttpHeaders headers = request.getHeaders();
        if (headers != null) {
            Map<String, String> headerMap = headers.toSingleValueMap();
            requestInfo.append("[header => ");
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                String headerName = entry.getKey();
                requestInfo.append(headerName).append(":");
                requestInfo.append(entry.getValue());
                requestInfo.append(",");
            }
            requestInfo.append("]").append("   ");
        }
    }

    /**
     * 获取所有参数
     * @author liaogang
     * @date 2020/9/16
     * @param request
     * @param requestInfo
     * @return void
     */
    private void getParameters(ServerHttpRequest request, StringBuilder requestInfo) {
        MultiValueMap<String, String> params = request.getQueryParams();
        if (params != null) {
            requestInfo.append("[parameter => ");
            for (Map.Entry<String, List<String>> param : params.entrySet()) {
                String headerName =  param.getKey();
                requestInfo.append(headerName).append(":");
                requestInfo.append(param.getValue());
                requestInfo.append(",");
            }
            requestInfo.append("]");
        }
    }
}
